package com.hy.frame.net

import android.os.Handler
import android.os.Looper
import com.hy.frame.bean.DownFile
import com.hy.frame.util.MyLog
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import okhttp3.ResponseBody
import java.io.*

/**
 * title 文件下载 非主线程
 * author heyan
 * time 18-12-4 上午11:23
 * desc 包含断点限速功能
 * @param listener 回调
 * @param savePath 保存路径
 * @param isNeedProgress 是否反馈下载进度，此时onSuccess中mDownFile.state==DownFile.STATUS_PROGRESS
 * @param renewal 是否开启断点下载功能
 * @param limitSpeed 每秒限制速度(单位B)，0时不限速
 */
open class FileObserver(private val listener: ICallback?, private val savePath: String?, private val isNeedProgress: Boolean = false, private val renewal: Boolean = false, private val limitSpeed: Long = 0L) : Observer<ResponseBody> {

    private var disposable: Disposable? = null
    private var lastNotifyTime = 0L

    private val dFile = DownFile()

    override fun onComplete() {
        MyLog.d(javaClass, "onComplete")
    }

    override fun onSubscribe(d: Disposable) {
        //MyLog.e("onSubscribe$d")
        this.disposable = d
    }

    override fun onNext(response: ResponseBody) {
        MyLog.d(javaClass, "onNext")
        //val contentType = response.contentType().toString()
        if (savePath == null) {
            onRequestError(0, "未定义文件存储路径")
            return
        }
        MyLog.d(javaClass, "savePath=$savePath")
        dFile.filePath = savePath
        dFile.state = DownFile.STATUS_START
        val file = File(savePath)
        val tempFile = File(savePath + EXT_TEMP)
        var tempSize = 0L
        if (renewal && tempFile.exists()) {
            tempSize += tempFile.length()
        }
        var inputStream: InputStream? = null
        var outputStream: OutputStream? = null
        try {
            val fileReader = ByteArray(1024) //1024b = 1kb
            val fileSize: Long = response.contentLength()
            var downloadSize: Long = 0
            dFile.state = DownFile.STATUS_PROGRESS
            dFile.fileSize = fileSize + tempSize
            inputStream = response.byteStream()
            outputStream = FileOutputStream(tempFile, renewal)
            var read: Int
            var downloadCache = 0L
            var time = 0L
            while (true) {
                read = inputStream?.read(fileReader) ?: -1
                if (read == -1) {
                    break
                }
                outputStream.write(fileReader, 0, read)
                downloadSize += read
                downloadCache += read
                time = System.currentTimeMillis()
                //进度反馈
                if (isNeedProgress && time - lastNotifyTime >= TIME_NOTIFY) {
                    lastNotifyTime = time
                    dFile.downloadSize = downloadSize + tempSize
                    //MyLog.d(javaClass, "file download:$downloadSize/$fileSize read=$read")
                    onRequestSuccess(DownFile.STATUS_PROGRESS, dFile)
                }
                //限速 必须大于1kb
                if (limitSpeed > 1000L) {
                    if (downloadCache >= limitSpeed / 10) {
                        downloadCache = 0
                        Thread.sleep(THREAD_SPLEEP)
                    }
                }
            }
            outputStream.flush()
            dFile.state = DownFile.STATUS_SUCCESS
            tempFile.renameTo(file)
            MyLog.d(javaClass, "file download:$downloadSize/$fileSize success")
            onRequestSuccess(DownFile.STATUS_SUCCESS, dFile)
            return
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            try {
                inputStream?.close()
                outputStream?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        onRequestError(0, "网络异常，请稍后重试")
    }

    override fun onError(e: Throwable) {
        MyLog.e(javaClass, "onError$e")
        onRequestError(0, "网络异常，请稍后重试")
    }

    private fun onRequestError(code: Int, msg: String?) {
        MyLog.d(javaClass, "onRequestError")
        this.disposable?.dispose()
        Handler(Looper.getMainLooper()).post {
            listener?.onError(code, msg)
        }
    }

    private fun onRequestSuccess(status: Int, file: DownFile) {
        if (status == DownFile.STATUS_SUCCESS)
            this.disposable?.dispose()
        Handler(Looper.getMainLooper()).post {
            listener?.onSuccess(file, null)
        }
    }

    interface ICallback {
        fun onSuccess(obj: DownFile, msg: String?)
        fun onError(errorCode: Int, msg: String?)
    }

    companion object {
        const val TIME_NOTIFY = 200L //通知进度间隔
        const val THREAD_SPLEEP = 100L //限速间隔
        const val EXT_TEMP = "c"
    }
}